/*
 * @Description: 
 * @FilePath: /STM32/USER/bsp/spi.h
 * @Author: Wei Zhou
 * @Github: https://github.com/zromyk
 * @Date: 2021-04-28 15:25:19
 * @LastEditors: Wei Zhou
 * @LastEditTime: 2021-04-28 22:01:03
 * @Copyright: Copyright  2017 muyiro. All rights reserved.
 */

#ifndef SPI_INIT_H
#define SPI_INIT_H

#include "my_include.h"
#include "dma.h"
#include "gpio.h"

/*
| APB1 (168MHz)  | APB2 (84MHz)  | AHB1 (168MHz)  | AHB2 (168MHz)  |
| -------------- | ------------- | -------------- | -------------- |
|                | SPI1          |                |                |
| SPI2           |               |                |                |
| SPI3           |               |                |                |
|                | SPI4          |                |                |
|                | SPI5          |                |                |
|                | SPI6          |                |                |
*/

typedef struct 
{
    SPI_TypeDef     * const SPIx;
    uint32_t        const RCC_Periph_SPI;
    PIN_Dev         const pin_nss;
    PIN_Dev         const pin_sck;
    PIN_Dev         const pin_miso;
    PIN_Dev         const pin_mosi;
    
    uint8_t         * const tx_buf;
    uint8_t         * const rx_buf;
    uint32_t        const tx_buf_size;
    uint32_t        const rx_buf_size;
    uint32_t        rx_cnt;
    
    IRQn_Type       const SPIx_IRQn;
    
    DMA_Dev         dma;
} SPI_Dev;

/* Exported macro ------------------------------------------------------------*/

#define TxBuffer_Size_SPI1   32
#define RxBuffer_Size_SPI1   32

#define TxBuffer_Size_SPI2   32
#define RxBuffer_Size_SPI2   32

extern uint8_t TxBuffer_SPI1[TxBuffer_Size_SPI1];
extern uint8_t RxBuffer_SPI1[RxBuffer_Size_SPI1];

extern uint8_t TxBuffer_SPI2[TxBuffer_Size_SPI2];
extern uint8_t RxBuffer_SPI2[RxBuffer_Size_SPI2];

extern SPI_Dev spi1;
extern SPI_Dev spi2;

/* Exported functions ------------------------------------------------------- */

typedef enum
{
    Master = SPI_Mode_Master,
    Slave  = SPI_Mode_Slave
} SPI_Master_Slave;

typedef enum
{
    Mode0_CPOL0_CPHA0,
    Mode1_CPOL0_CPHA1,
    Mode2_CPOL1_CPHA0,
    Mode3_CPOL1_CPHA1,
} SPI_Mode;

/**
 * @brief  spi initialize.
 * @param  *spi: point to a SPI_Dev.
 * @param  master_slave: select from SPI_Master_Slave.
 * @param  mode: select from SPI_Mode.
 * @retval None
 */
void spi_init(SPI_Dev *spi, SPI_Master_Slave master_slave, SPI_Mode mode);

/**
 * @brief  spi initialize.
 * @param  *spi: point to a SPI_Dev.
 * @param  SPI_InitStruct: point to a SPI_InitTypeDef.
 * @retval None
 */
void spi_user_define_init(SPI_Dev *spi, SPI_InitTypeDef *SPI_InitStruct);

/**
 * @brief  spi rx initialize.
 * @param  *spi: point to a SPI_Dev.
 * @param  priority:    主优先级
 * @param  subPriority: 子优先级
 * @retval None
 */
void spi_it_rx_init(SPI_Dev *spi, uint8_t priority, uint8_t subPriority);

/* spi dma functions ------------------------------------------------------- */
/**
 * @brief  初始化 DMA 接收，包含 DMA 接收中断.
 * 注意：在初始化 DMA 之前，需要先初始化 SPI (spi_init)
 * @param  *spi: point to a SPI_Dev.
 * @retval None
 */
void spi_dma_rx_init(SPI_Dev *spi);

/**
 * @brief  初始化 DMA 发送
 * 注意：在初始化 DMA 之前，需要先初始化 SPI (spi_init)
 * @param  *spi: point to a SPI_Dev.
 * @retval None
 */
void spi_dma_tx_init(SPI_Dev *spi);

/**
 * @brief  使能 DMA 发送
 * @param  *spi: point to a SPI_Dev.
 * @param  size: the length of buffer. (buffer is spi->tx_buf)
 * @retval None
 */
void spi_dma_tx_size_enable(SPI_Dev *spi, uint32_t size);

/**
 * @brief  使能 DMA 发送，发送缓冲区内的所有数据
 * @param  *spi: point to a SPI_Dev.
 * @retval None
 */
void spi_dma_tx_enable(SPI_Dev *spi); // send full buffer.

/* Send information functions ------------------------------------------------ */
/**
 * @brief  write 1 byte.
 * @param  *spi: point to a SPI_Dev.
 * @param  byte: the byte send to SPI Slave.
 * @retval None
 */
void spi_write_byte(SPI_Dev *spi, const uint8_t byte);

/**
 * @brief  read 1 byte.
 * @param  *spi: point to a SPI_Dev.
 * @retval the byte read.
 */
uint8_t spi_read_byte(SPI_Dev *spi);

/**
 * @brief  write buffer.
 * @param  *spi:    point to a SPI_Dev.
 * @param  *buf:    send buffer.
 * @param  length:  the length of buffer.
 * @retval None.
 */
void spi_write_buffer(SPI_Dev *spi, const uint8_t *buf, uint32_t length);

/**
 * @brief  write an read buffer.
 * @param  *spi:    point to a SPI_Dev.
 * @param  *tx:     send buffer.
 * @param  *rx:     receive buffer.
 * @param  length:  the length of buffer.
 * @retval None.
 */
void spi_transfer(SPI_Dev *spi, uint8_t *tx, uint8_t *rx, uint32_t length);

#endif /* SPI_INIT_H */
